﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Threading.Tasks;
using FinPlusCommon;
using log = Logger.Logger;
using u = FinPlusUtility.Utility;

namespace FinPlusComponents
{
    public class QLParseBondTrade : FinPlusComponent
    {
        public override string Id { get; set; }
        public override string[] States { get { return new string[] { }; } }
        public override string[] TestStates { get { return new string[] { "IsValid" }; } }
        public override IFinPlusFunctions Model { get { return null; } }
        public override string ModelTest { get { return null; } }
        public override bool IsValid { get; set; }

        private enum Params { ParseTradeAction, ResponseAction, Bond, BuySell, Instrument, Settle, QuoteAccept, QuoteRef, TradeId, Quote, Size, FunctionName, FixedRateBond, FloatingRateBond, ZeroCouponBond, Book, Counterparty, MarketName, CacheName, TempId, BondName, CurveName, Nominal, Settlement, Price }
        private enum BondBuilds { FixedRateBondBuild, FloatingRateBondBuild, ZeroCouponBondBuild, Bond }
        private enum DockControls { FinPlusDataConn, FinPlusChildService, Default }
        private enum Connection { TradeAdaptors, InstrumentBuilds, TradeSave, Exception }
        
        private IFinPlusComponent _instrumentBuildConn, _tradeAdaptorConn;
        private FinPlusDataConn _tradeSaveConn;
        private IFinPlusFunction _tradeAdaptor;
        private bool _hasInitialised;

        //construct
        public QLParseBondTrade(){}

        //common control interface
        public override void Dock(object component, string dock)
        {
            try
            {
                switch (u.EnumTryParse<DockControls>(component.GetType().Name, DockControls.Default))
                {
                    case DockControls.FinPlusChildService:
                    case DockControls.FinPlusDataConn:
                    case DockControls.Default: AddConnection((IFinPlusComponent)component, dock); break;
                }
            }
            catch (Exception e)
            {
                IsValid = log.Log(Logger.Level.Error, Id, Config, e.Message, e);
            }
        }

        public override void Initialise()
        {
            if (_hasInitialised) return;

            _tradeAdaptor = _tradeAdaptorConn.Model.First("Name='InstrumentType' And Value='Bond'");
            _tradeAdaptor.Get(Params.ParseTradeAction.ToString(), Parse_Trade);

            IsValid = _hasInitialised = true;
        }

        public override void Dispose()
        {
            try
            {
                if (_tradeSaveConn != null)
                    _tradeSaveConn.Dispose();
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Warning, e.Message, e);
            }
        }

        public override void CommandRouter(IFinPlusFunction func)
        {
            try
            {
                CaptureCommand(func);

                switch ((Commands)Enum.Parse(typeof(Commands), func.Name, true))
                {
                    case Commands.QuoteAccept: ExecutionParse(func); break;
                    case Commands.QuoteAcceptPublish: ExecutionParse(func); break;
                    default: throw new Exception(string.Format("event not recognised {0}", func.Name));
                }
            }
            catch (Exception e)
            {
                IsValid = log.Log(Logger.Level.Error, Id, Config, e.Message, e);
            }
        }

        //private
        private void AddConnection(IFinPlusComponent conn, string dock)
        {
            switch (u.EnumTryParse<Connection>(dock, Connection.Exception))
            {
                case Connection.TradeAdaptors: _tradeAdaptorConn = conn; break;
                case Connection.InstrumentBuilds: _instrumentBuildConn = conn; break;
                case Connection.TradeSave: _tradeSaveConn = (FinPlusDataConn)conn; break;
                case Connection.Exception: throw new NotImplementedException();
            }
        }

        private bool ExecutionParse(IFinPlusFunction func)
        {
            try
            {
                //trade parse
                var instrument = func[Params.Instrument.ToString()].ToString();
                var instrumentBuild = _instrumentBuildConn.Model.First("Name='Instrument' And Value='" + instrument + "'");

                IFinPlusFunction trade;
                switch (u.EnumTryParse<BondBuilds>(instrumentBuild[Params.FunctionName.ToString()].ToString(), BondBuilds.Bond))
                {
                    case BondBuilds.FixedRateBondBuild: trade = new Function(Params.FixedRateBond.ToString()); break;
                    case BondBuilds.FloatingRateBondBuild: trade = new Function(Params.FloatingRateBond.ToString()); break;
                    case BondBuilds.ZeroCouponBondBuild: trade = new Function(Params.ZeroCouponBond.ToString()); break;
                    default: trade = new Function(Params.Bond.ToString()); break;
                }

                trade.Add(Params.Book.ToString(), func[Params.Book.ToString()].ToString());
                trade.Add(Params.Counterparty.ToString(), func[Params.Counterparty.ToString()].ToString());
                trade.Add(Params.MarketName.ToString(), string.Empty);
                trade.Add(Params.CacheName.ToString(), string.Empty);
                trade.Add(Params.TradeId.ToString(), func[Params.QuoteRef.ToString()].ToString());
                trade.Add(Params.BondName.ToString(), func[Params.Instrument.ToString()].ToString());
                trade.Add(Params.CurveName.ToString(), string.Empty);

                if(func.Name.Equals(Params.QuoteAccept.ToString()))
                    trade.Add(Params.Nominal.ToString(), (func[Params.BuySell.ToString()].Equals("Buy") ? -1 : 1) * (double)func.Value(Params.Size.ToString()));
                else
                    trade.Add(Params.Nominal.ToString(), (func[Params.BuySell.ToString()].Equals("Buy") ? 1 : -1) * (double)func.Value(Params.Size.ToString()));
                
                trade.Add(Params.Settlement.ToString(), (DateTime)func.Value(Params.Settle.ToString()));
                trade.Add(Params.Price.ToString(), (double)func.Value(Params.Quote.ToString()));

                //save bond
                _tradeSaveConn.Save(trade);

                //respond with trade for testing
                trade.Add(Params.Instrument.ToString(), instrument); 
                _tradeAdaptor.Get(Params.ResponseAction.ToString()).Set(trade);

                return true;
            }
            catch (Exception e)
            {
                return IsValid = log.Log(Logger.Level.Error, func.ToString(), e);
            } 
        }

        //cmds
        private new enum Commands { QuoteAccept, QuoteAcceptPublish };

        //events
        private void Parse_Trade(object sender, PropertyChangedEventArgs a) { CommandRouter((IFinPlusFunction)((IFinPlusItem)sender).Object); }//QuoteAccept && QuotePublishAccept
    }
}
